package com.cc.plugin;

import java.util.Properties;

import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts(@Signature(
        type = Executor.class, 
        method = "query", 
        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class ExamplePlugin implements Interceptor {
  private Properties properties = new Properties();
  public Object intercept(Invocation invocation) throws Throwable {
    // implement pre processing if need
      System.out.println("开始拦截 ");
      Object[] args = invocation.getArgs();
      MappedStatement ms = (MappedStatement) args[0];
      Object parameterObject = args[1];
      BoundSql boundSql = ms.getBoundSql(parameterObject);
      String sql= boundSql.getSql();
      sql = sql  +  " limit 1";
   // 重新new一个查询语句对像
      BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject());
      // 把新的查询放到statement里
      MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
      
      for (ParameterMapping mapping : boundSql.getParameterMappings()) {
          String prop = mapping.getProperty();
          if (boundSql.hasAdditionalParameter(prop)) {
              newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
          }
      }
      args[0] = newMs;
      args[1]=28;
      
    Object returnObject = invocation.proceed();
    System.out.println("拦截结束！！");
    // implement post processing if need
    return returnObject;
  }
  public void setProperties(Properties properties) {
    this.properties = properties;
  }
  @Override
  public Object plugin(Object target) {
      return Plugin.wrap(target, this);
  }
  
  
  private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
      MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
      builder.resource(ms.getResource());
      builder.fetchSize(ms.getFetchSize());
      builder.statementType(ms.getStatementType());
      builder.keyGenerator(ms.getKeyGenerator());
      if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
          builder.keyProperty(ms.getKeyProperties()[0]);
      }
      builder.timeout(ms.getTimeout());
      builder.parameterMap(ms.getParameterMap());
      builder.resultMaps(ms.getResultMaps());
      builder.resultSetType(ms.getResultSetType());
      builder.cache(ms.getCache());
      builder.flushCacheRequired(ms.isFlushCacheRequired());
      builder.useCache(ms.isUseCache());
      return builder.build();
  }
  public static class BoundSqlSqlSource implements SqlSource {
      private BoundSql boundSql;
      public BoundSqlSqlSource(BoundSql boundSql) {
          this.boundSql = boundSql;
      }
      public BoundSql getBoundSql(Object parameterObject) {
          return boundSql;
      }
  }

}